#include "stdafx.h"
#include "NetworkManager.h"
#include <assert.h>
#include "IPAddress.h"
#include "../EdgeMath/Vectors.h"
#include "../EdgeGameCore/World/Chunk.h"
#include "../EdgeGameCore/World/ChunkManager.h"
#include <vector>
#include "../EdgeGameCore/Objects/IAgent.h"
#include "../EdgeGameCore/Objects/ObjectManager.h"
#include "../EdgeGameCore/Objects/ControlableGameObject.h"
using namespace std;

#define cast(ptr, type) reinterpret_cast<type*>(ptr)

NetworkManager::NetworkManager(void)
{

}

NetworkManager::~NetworkManager(void)
{
	WSACleanup();
	if (server != INVALID_SOCKET)
		closesocket(server);
}

void NetworkManager::ConnectToSession(IPAddress ipAddress)
{
	WSAData data;
	int result = WSAStartup(MAKEWORD(2, 2), &data);
	assert(result == 0 && "Failed to inilitize server");

	addrinfo address_info;
	PADDRINFOA localAddressInfo = nullptr;
	ZeroMemory(&address_info, sizeof(addrinfo));
	address_info.ai_family = AF_UNSPEC;
	address_info.ai_socktype = SOCK_STREAM;
	address_info.ai_protocol = IPPROTO_TCP;

	result = getaddrinfo(ipAddress.getAddress(), DEFAULT_PORT, &address_info, &localAddressInfo);
	assert(result == 0 && "Failed to get local address info");

	server = socket(localAddressInfo->ai_family, localAddressInfo->ai_socktype, localAddressInfo->ai_protocol);
	assert(server != INVALID_SOCKET && "Failed to create socket");

	result = connect(server, localAddressInfo->ai_addr, localAddressInfo->ai_addrlen);
	if (result == INVALID_SOCKET)
	{
		cout << "Client was unable to connect to server. Error code: " << WSAGetLastError();
		closesocket(server);
		return;
	}

	FreeAddrInfoA(localAddressInfo);
	
	char sendBuffer[DEFAULT_CLIENT_REQUEST_SIZE];
	ZeroMemory(&sendBuffer, DEFAULT_CLIENT_REQUEST_SIZE);

	*cast(sendBuffer, int) = MSG_CLIENT_CONNECT;
	result = send(server, sendBuffer, DEFAULT_CLIENT_REQUEST_SIZE, 0);
	assert(result != SOCKET_ERROR && "Failed to send data to server");

	connectedToGame = true;	
}

void NetworkManager::DisconnectSession(void)
{
	if (server != INVALID_SOCKET)
		closesocket(server);
	WSACleanup();

	connectedToGame = false;
}

void NetworkManager::Update(float dt)
{
	if (connectedToGame)
	{
		int bytesRecieved = 0;
		do
		{
			bytesRecieved = recv(server, serverBuffer, DEFAULT_BUFFER_LENGTH, 0);
			if (bytesRecieved < 0)
				cout << "Failed to recieve data from server" << endl;
		} while (bytesRecieved < DEFAULT_BUFFER_LENGTH);

		ChunkManager* pChunkManager = ChunkManager::GetInstance();
		Chunk* curChunk = pChunkManager->getActiveChunk();
		ObjectManager* pObjects = curChunk->getObjectManager();

		for (int i = 0; i < pObjects->getNumAgents(); i++)
		{
			Agent* curAgent = pObjects->getAgent(i);
			Vector3 position = *cast(serverBuffer + 4 + (i * sizeof(Vector3)), Vector3);
			curAgent->getTarget()->setPosition(position);
		}
	}
}